package de.medieninf.sensimg;

import java.util.Enumeration;
import java.util.Vector;


/**
 * Simple Logger, allows logging of text messages.
 * @author pb
 */
public final class Logger {
    /**
     * Minimal number of entries.
     * While deleting leave that many in the log.
     */
    static final int MIN_ENTRIES = 20;
    /**
     * Maximal number of entries.
     * If there are more than that entries, delete.
     */
    static final int MAX_ENTRIES = 40;

    /**
     * lock object for concurrent access of log.
     */
    private static Object lock = new Object();
    /**
     * Vector storing the log messages.
     */
    private static Vector log = new Vector();
    /**
     * The observers being notified on adding a log message.
     */
    private static Vector observers = new Vector();
    /**
     * Cache of last element of the log.
     */
    private static String lastElement;
    /**
     * Whether to do logging at all.
     */
    private static volatile boolean doLog = true;
    /**
     * Current number of entries.
     */
    private static int noEntries = 0;

    /**
     * Add a log message.
     * @param s String, the log message
     */
    public static void log(final String s) {
        if (!doLog) {
            return;
        }
        int removes = 0;
        synchronized (lock) {
            log.addElement(s);
            lastElement = s;
            noEntries += 1;
            if (noEntries >= MAX_ENTRIES) {
                removes = log.size() - MIN_ENTRIES;
                noEntries -= removes;
            }
        }
        if (removes > 0) {
            for (int i = 0; i < removes; i++) {
                // can be slow, but parallel access works
                log.removeElementAt(0);
            }
        }
        Enumeration enumeration = observers.elements();
        while (enumeration.hasMoreElements()) {
            Runnable r = (Runnable) enumeration.nextElement();
            r.run();
        }
    }

    /**
     * Starts logging.
     */
    public static void doLog() {
        doLog = true;
    }

    /**
     * Stops logging.
     */
    public static void dontLog() {
        doLog = false;
    }

    /**
     * Gets last log message from cache.
     * @return last log message iff available.
     */
    public static String getLast() {
        return lastElement;
    }

    /**
     * Gets last i log messages.
     * @param pi int, how many
     * @return concatenation of log messages, separated by \n
     */
    public static String getLast(final int pi) {
        int i = pi;
        StringBuffer ret = new StringBuffer();
        synchronized (lock) {
            int size = log.size();
            if (size < i) {
                i = size;
            }
            while (i > 0) {
                ret.append(log.elementAt(size - i));
                ret.append("\n");
                i -= 1;
            }
        }
        return ret.toString();
    }

    /**
     * Clears all log messages (keeps last log message).
     */
    public static void clear() {
        synchronized (lock) {
            log.removeAllElements();
        }
    }

    /**
     * Registers observer to be notified if log message is added.
     * @param r Runnable to be added as observer.
     */
    public static void register(final Runnable r) {
        observers.addElement(r);
    }

    /**
     * Unregisters observer to be notified if log message is added.
     * @param r Runnable to be removed as observer.
     */
    public static void unregister(final Runnable r) {
        observers.removeElement(r);
    }

    /**
     * Registers an observer logging on standard out.
     */
    public static void logOnConsole() {
        register(new Runnable() {
            public void run() {
            	// Findbugs reports problem - is fine.
                System.out.println(getLast());
            }
        });
    }

    /**
     * Do not construct an instance.
     */
    private Logger() {
    }
}
